前面學習到的 FSM ,我們透過枚舉、列舉 (Enumerate),一個狀態機內所有可能的狀態,狀態機被提供的狀態是有限(Finite)的,所以叫我們稱之為有限狀態機 (Finite State Machine)。
但現實中的狀態機裡,我們可能會有些狀態是無限的、或是我們希望能帶某些資料(data)進去狀態機裡供其使用...
我們將這些無窮的狀態、資料稱之為 "Extended State"(擴充的狀態)。
比如說有一個水的狀態機,水可能會有「液態」、「固態」、「氣態」的三種狀態,但有時我們希望這組狀態機也能儲存當前水容量(amount)的資訊,這個水容量無法用 1,2,3... 列舉完,水量可能是無窮盡的。
在 XState 裡面的 Extended State 被稱作 "context"
我們繼續以底下這個狀態機為範例
我們要怎麼帶額外的資料進去狀態機內呢?
比如說這個門可能是屬於不同家店的,可能會有店名像是「綠洲酒吧」、「蘋果旗艦店」或是任何使用者輸入...,我們一時間無法列舉出所有可能...,但當我在判斷狀態轉換的防禦(Guard)、又或是執行 side effect 的 action 需要這個資料時,該怎麼辦?
我們一樣可以把這個資料寫進去 machineConfig
const doorMachine = createMachine(
{
// Machine identifier
id: "door",
// Initial context
+ context: {
+ shopName: "蘋果旗艦店"
+ },
// Initial state
initial: "關著",
// State definitions
states: {...}
}, extraOptions)
接下來我們在回去看昨天的 Action
{
actions: {
拉開大門: (c, e) =>
console.error("side effect..........拉開厚重的門...."),
關上大門: () => console.error("side effect..........推回厚重的門....")
}
}
有注意到『拉開大門』這個 side effect ,的 (c, e)
終於可以在今天一起介紹了,那個 c
就是 context(Extended State); e
就是 event (事件),也就是當我們在執行『拉開大門』時,我們可以拿到狀態機裡的資料及當下這個事件,我們可以直切印出 c,e
看看
{
actions: {
拉開大門: (c, e) =>
- console.error("side effect..........拉開厚重的門...."),
+ console.error(c, e, "side effect..........拉開厚重的門...."),
關上大門: () => console.error("side effect..........推回厚重的門....")
}
}
如此我們就能拿到這個被延伸、被狀態機記憶且共享的資料了
比如說我們這台狀態機想要給許多不同的店家共用,比如「綠洲酒吧」、「蘋果旗艦店」...
難道我需要一直寫一堆 appleStoreMachineConfig
, oasisBarMachineConfig
卻只有 context 些微不一樣嗎?
比如說今天我們「蘋果旗艦店」想要改店名成「蘋果尊絕不凡旗艦店」,我可以直接在狀態機裡面修改 context value 嗎?
這兩個問題將在明天一起被回答~
https://en.wikipedia.org/wiki/UML_state_machine
https://xstate.js.org/docs/guides/context.html#initial-context